<template>
  <label class="switch" :class="{ 'is-disabled': field.disabled, 'switch--wide': hasText, 'is-checked': checked }">
    <div class="switch__mask" v-show="field.disabled"></div>
    <input
      class="switch__input"
      type="checkbox"
      @change="handleChange"
      ref="input"
      :name="field.name"
      :true-value="field.onValue"
      :false-value="field.offValue"
      :disabled="field.disabled">
    <span class="switch__core" ref="core" :style="{ 'width': coreWidth + 'px' }">
      <span class="switch__button" :style="{ transform }"></span>
    </span>
    <transition name="labfade">
      <div
        class="switch__label switch__lab-left"
        v-show="checked"
        :style="{ 'width': coreWidth + 'px' }">
        <i :class="[field.onIconClass]" v-if="field.onIconClass"></i>
        <span v-if="!field.onIconClass && field.onText">{{ field.onText }}</span>
      </div>
    </transition>
    <transition name="labfade">
      <div
        class="switch__label switch__lab-right"
        v-show="!checked"
        :style="{ 'width': coreWidth + 'px' }">
        <i :class="[field.offIconClass]" v-if="field.offIconClass"></i>
        <span v-if="!field.offIconClass && field.offText">{{ field.offText }}</span>
      </div>
    </transition>
  </label>
</template>

<script>
  export default {
    name: 'ElSwitch',
    props: {
      value: {
        type: [Boolean, String, Number],
        default: false
      },
      field: {
        disabled: {
          type: Boolean,
          default: false
        },
        width: {
          type: Number,
          default: 0
        },
        onIconClass: {
          type: String,
          default: ''
        },
        offIconClass: {
          type: String,
          default: ''
        },
        onText: {
          type: String,
          default () { return 'ON' }
        },
        offText: {
          type: String,
          default: 'OFF'
        },
        onColor: {
          type: String,
          default: ''
        },
        offColor: {
          type: String,
          default: ''
        },
        onValue: {
          type: [Boolean, String, Number],
          default: true
        },
        offValue: {
          type: [Boolean, String, Number],
          default: false
        },
        name: {
          type: String,
          default: ''
        }
      }
    },
    data () {
      return {
        coreWidth: this.field.width
      }
    },
    created () {
      if (!~[this.field.onValue, this.field.offValue].indexOf(this.value)) {
        this.$emit('input', this.field.offValue)
      }
    },
    computed: {
      checked () {
        return this.value === this.field.onValue
      },
      hasText () {
        /* istanbul ignore next */
        return this.field.onText || this.field.offText
      },
      transform () {
        return this.checked ? `translate(${this.coreWidth - 20}px, 2px)` : 'translate(2px, 2px)'
      }
    },
    watch: {
      checked () {
        if (this.field.onColor || this.field.offColor) {
          this.setBackgroundColor()
        }
      }
    },
    methods: {
      handleChange (event) {
        this.$emit('change', !this.checked ? this.field.onValue : this.field.offValue)
        this.$emit('input', !this.checked ? this.field.onValue : this.field.offValue)
        this.$nextTick(() => {
          // set input's checked property
          // in case parent refuses to change component's value
          this.$refs.input.checked = this.checked
        })
      },
      setBackgroundColor () {
        let newColor = this.checked ? this.field.onColor : this.field.offColor
        this.$refs.core.style.borderColor = newColor
        this.$refs.core.style.backgroundColor = newColor
      }
    },
    mounted () {
      /* istanbul ignore if */
      if (this.field.width === 0) {
        this.coreWidth = this.hasText ? 58 : 46
      }
      if (this.field.onColor || this.field.offColor) {
        this.setBackgroundColor()
      }
      this.$refs.input.checked = this.checked
    }
  }
</script>

<style>
  .switch {
    display: inline-block;
    position: relative;
    font-size: 14px;
    line-height: 22px;
    height: 22px;
    vertical-align: middle;
  }
  .switch__label, .switch__label * {
    position: absolute;
    display: inline-block;
    font-size: 14px;
  }
  .switch__input {
    display: none;
  }
  .switch__label {
    transition: .2s;
    width: 46px;
    height: 22px;
    left: 0;
    top: 0;
    cursor: pointer;
  }

  .switch.is-checked .switch__core {
    border-color: #20a0ff;
    background-color: #20a0ff;
  }

  .switch__core {
    margin: 0;
    display: inline-block;
    position: relative;
    width: 46px;
    height: 22px;
    border: 1px solid #bfcbd9;
    outline: none;
    border-radius: 12px;
    box-sizing: border-box;
    background: #bfcbd9;
    cursor: pointer;
    transition: border-color .3s,background-color .3s;
  }

  .switch__core .switch__button {
    top: 0;
    left: 0;
    position: absolute;
    border-radius: 100%;
    transition: transform .3s;
    width: 16px;
    height: 16px;
    background-color: #fff;
  }

  .switch--wide .switch__label.switch__lab-left span {
    left: 10px;
  }

  .switch--wide .switch__label.switch__lab-right span {
    right: 10px;
  }

  .switch__label * {
    line-height: 1;
    top: 4px;
    color: #fff;
  }

  .switch__label, .switch__label * {
    position: absolute;
    display: inline-block;
    font-size: 14px;
  }

  .switch.is-disabled .switch__core {
    border-color: #e4e8f1!important;
    background: #e4e8f1!important;
  }

</style>